home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / tdk_v120.zip / ASYNC.PAS < prev    next >
Pascal/Delphi Source File  |  1996-07-15  |  61KB  |  1,197 lines

  1. {
  2.  ▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀    ▀▀   ▀▀
  3.    ▀▀     ▀▀   ▀▀   ▀▀  ▀▀
  4.   ▀▀     ▀▀   ▀▀▀  ▀▀▀▀▀  The DoorKit!
  5.  ▀▀     ▀▀   ▀▀   ▀▀  ▀▀
  6. ▀▀     ▀▀▀▀▀▀    ▀▀    ▀▀
  7. The BBS Door Development Kit By The People - For The People!
  8.  
  9.  
  10.    Feel free to modify or optimize this code at will. All I ask is that if
  11.    find a better way to do things (and you will), please send me a copy of
  12.    your modifications. Thanks in advance!....Larry L. Athey....}
  13.  
  14. {*--------------------------------------------------------------------------*}
  15. {*                                                                          *}
  16. {*  Status byte definition (C_Status):                                      *}
  17. {*                                                                          *}
  18. {*  7   6   5   4   3   2   1   0                                           *}
  19. {*  |   |   |   |   |   |   |   |____ Input buffer empty                    *}
  20. {*  |   |   |   |   |   |   |________ Input buffer full                     *}
  21. {*  |   |   |   |   |   |____________ Output buffer empty                   *}
  22. {*  |   |   |   |   |________________ Output buffer full                    *}
  23. {*  |   |   |   |____________________ Input buffer overflow                 *}
  24. {*  |   |   |________________________ Output buffer overflow                *}
  25. {*  |   |____________________________ Hard handshake active (xmit stopped)  *}
  26. {*  |________________________________ Soft handshake active (xmit stopped)  *}
  27. {*                                                                          *}
  28. {*  Control byte definition (C_Ctrl):                                       *}
  29. {*                                                                          *}
  30. {*  7   6   5   4   3   2   1   0                                           *}
  31. {*  |   |   |   |   |   |   |   |____ Enable RTS handshake                  *}
  32. {*  |   |   |   |   |   |   |________ Enable CTS handshake                  *}
  33. {*  |   |   |   |   |   |____________ Enable software handshake             *}
  34. {*  |   |   |   |   |________________                                       *}
  35. {*  |   |   |   |____________________                                       *}
  36. {*  |   |   |________________________                                       *}
  37. {*  |   |____________________________                                       *}
  38. {*  |________________________________                                       *}
  39. {*                                                                          *}
  40. {****************************************************************************}
  41.  
  42. {$R-,V-,B-,S-}
  43.  
  44. Unit ASYNC;
  45.  
  46. INTERFACE
  47.  
  48. {----------------------------------------------------------------------------}
  49.  
  50. CONST
  51.   C_MinBaud  = 300;
  52.   C_MaxBaud  = 115200;
  53.   C_MaxPort  = 4;
  54.   C_MaxCom   : BYTE = C_MaxPort;
  55.   C_PortAddr : ARRAY[1..C_MaxPort] OF WORD = ($03F8,$02F8,$03E8,$02E8);
  56.   C_PortInt  : ARRAY[1..C_MaxPort] OF BYTE = (4,3,4,3);
  57.  
  58. {----------------------------------------------------------------------------}
  59.  
  60. TYPE
  61.   C_VectorArray  = ARRAY[0..15] OF POINTER;
  62.   C_PointerArray = ARRAY[1..C_MaxPort] OF POINTER;
  63.   C_WordArray    = ARRAY[1..C_MaxPort] OF WORD;
  64.   C_ByteArray    = ARRAY[1..C_MaxPort] OF BYTE;
  65.   C_CharArray    = ARRAY[1..C_MaxPort] OF CHAR;
  66.   C_BooleanArray = ARRAY[1..C_MaxPort] OF BOOLEAN;
  67.  
  68. {----------------------------------------------------------------------------}
  69.  
  70. VAR
  71.   { Base port addresses & interrupt usage }
  72. { C_PortAddr : Array[1..C_MaxPort] Of Word;
  73.   C_PortInt  : Array[1..C_MaxPort] Of Byte;{}
  74.   ComPort  : BYTE;
  75.   C_InBufPtr,C_OutBufPtr : C_PointerArray;    { Input/output buffer pointers }
  76.   C_InHead,C_OutHead     : C_WordArray;       { Input/output head pointers }
  77.   C_InTail,C_OutTail     : C_WordArray;       { Input/output tail pointers }
  78.   C_InSize,C_OutSize     : C_WordArray;       { Input/output buffer sizes }
  79.   C_RTSOn,C_RTSOff       : C_WordArray;       { RTS assert/drop buffer points }
  80.   C_StartChar,C_StopChar : C_CharArray;       { Soft hndshake start/stop char }
  81.   C_Status,C_Ctrl        : C_ByteArray;       { STATUS and CONTROL registers }
  82.   C_XL3Ptr               : C_ByteArray;
  83.   C_PortOpen             : C_BooleanArray;    { Port open/close flags }
  84.   C_Temp                 : WORD;              { Used for debugging }
  85.   C_msrport              : WORD;
  86. { RTSOn,RTSOff           : Word;              { RTS assert/drop buffer points }
  87. { oldier,oldmcr          : byte;}
  88.   c_oldier,c_oldmcr      : c_bytearray;
  89.   c_oldfcr               : c_bytearray;       { old FIFO status}
  90.   c_fifoOK               : c_booleanarray;
  91.   c_buffull              : c_wordarray;
  92. { C_Cascade              : Byte;              { Flag set 0 normally }
  93. { C_CascadeOK            : boolean;           { Flag if IRQ > 7 }
  94.   C_Cascade              : c_Bytearray;       { Flag set 0 normally }
  95.   C_CascadeOK            : c_booleanarray;    { Flag if IRQ > 7 }
  96.  
  97. {----------------------------------------------------------------------------}
  98.  
  99. FUNCTION  ComReadCh(ComPort : BYTE) : CHAR;
  100. FUNCTION  ComReadChW(ComPort : BYTE) : CHAR;
  101. { Procedure ComWriteCh(ComPort:Byte; Ch:Char); }
  102. PROCEDURE ComWriteChW(ComPort : BYTE; Ch : CHAR);
  103. PROCEDURE SetDTR(ComPort : BYTE; Assert : BOOLEAN);
  104. PROCEDURE SetRTS(ComPort : BYTE; Assert : BOOLEAN);
  105. { Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  106.   Procedure SetOUT2(ComPort:Byte; Assert:Boolean);}
  107. FUNCTION  CTSStat(ComPort : BYTE) : BOOLEAN;
  108. FUNCTION  RTSStat(ComPort : BYTE) : BOOLEAN;
  109. FUNCTION  DSRStat(ComPort : BYTE) : BOOLEAN;
  110. FUNCTION  RIStat(ComPort : BYTE) : BOOLEAN;
  111. FUNCTION  DCDStat(ComPort : BYTE) : BOOLEAN;
  112. PROCEDURE SetRTSMode(ComPort : BYTE; Mode : BOOLEAN; RTSOn,RTSOff : WORD);
  113. PROCEDURE SetCTSMode(ComPort : BYTE; Mode : BOOLEAN);
  114. PROCEDURE SoftHandshake(ComPort : BYTE; Mode : BOOLEAN; Start,Stop : CHAR);
  115. PROCEDURE ClearCom(ComPort : BYTE; IO : CHAR);
  116. FUNCTION  ComBufferLeft(ComPort : BYTE; IO : CHAR) : WORD;
  117. PROCEDURE ComWaitForClear(ComPort : BYTE);
  118. PROCEDURE I_ComWrite(ComPort : BYTE; St : STRING);
  119. PROCEDURE I_ComWriteln(ComPort : BYTE; St : STRING);
  120. PROCEDURE I_ComWriteWithDelay(ComPort : BYTE; St : STRING; Dly : WORD);
  121. PROCEDURE I_ComReadln(ComPort : BYTE; VAR St : STRING; Size : BYTE; Echo : BOOLEAN);
  122. FUNCTION  ComExist(ComPort : BYTE) : BOOLEAN;
  123. FUNCTION  ComTrueBaud(Baud : LONGINT) : REAL;
  124. PROCEDURE ComParams(ComPort : BYTE; Baud : LONGINT; WordSize : BYTE; Parity : CHAR; StopBits : BYTE);
  125. FUNCTION  OpenCom(ComPort : BYTE; InBufferSize,OutBufferSize : WORD) : BOOLEAN;
  126. PROCEDURE CloseCom(ComPort : BYTE);
  127. PROCEDURE CloseAllComs;
  128.  
  129. {----------------------------------------------------------------------------}
  130.  
  131. IMPLEMENTATION
  132.  
  133. Uses DOS,CRT;
  134.  
  135. {$L ASYNC.OBJ}
  136.  
  137. CONST
  138.   C_IER = 1;                           { 8250 register offsets }
  139.   C_IIR = 2;
  140.   C_LCR = 3;
  141.   C_MCR = 4;
  142.   C_LSR = 5;
  143.   C_MSR = 6;
  144.   C_SCR = 7;
  145.  
  146. VAR
  147.   C_OldINTVec : C_VectorArray;        { Storage for old hardware INT vectors }
  148.   X : BYTE;                           { Used by initialization code }
  149.  
  150. {****************************************************************************}
  151. {*                                                                          *}
  152. {*  Procedure INT_Handler; External;                                        *}
  153. {*                                                                          *}
  154. {*  Hardware interrupts 0-15 (vectors $08 - $0F,$70 - $77) are pointed to   *}
  155. {*  this routine.  It is for internal use only and should NOT be called     *}
  156. {*  directly.  Written in assembly language (see ASYNC.ASM).                *}
  157. {*                                                                          *}
  158. {****************************************************************************}
  159.  
  160. PROCEDURE INT_Handler; EXTERNAL;
  161.  
  162. {****************************************************************************}
  163. {*                                                                          *}
  164. {*  Procedure ComReadCh(ComPort:Byte) : Char; External;                     *}
  165. {*                                                                          *}
  166. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  167. {*                                                                          *}
  168. {*  Returns character from input buffer of specified port.  If the buffer   *}
  169. {*  is empty, the port # invalid or not opened, a Chr(0) is returned.       *}
  170. {*  Written in assembly language for best possible speed (see ASYNC.ASM)    *}
  171. {*                                                                          *}
  172. {****************************************************************************}
  173.  
  174. FUNCTION ComReadCh(ComPort : BYTE) : CHAR; EXTERNAL;
  175.  
  176. {****************************************************************************}
  177. {*                                                                          *}
  178. {*  Function ComReadChW(ComPort:Byte) : Char; External;                     *}
  179. {*                                                                          *}
  180. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  181. {*                                                                          *}
  182. {*  Works like ComReadCh, but will wait until at least 1 character is       *}
  183. {*  present in the specified input buffer before exiting.  Thus, ComReadChW *}
  184. {*  works much like the ReadKey predefined function.  Written in assembly   *}
  185. {*  language to maximize performance (see ASYNC.ASM)                        *}
  186. {*                                                                          *}
  187. {****************************************************************************}
  188.  
  189. FUNCTION ComReadChW(ComPort : BYTE) : CHAR; EXTERNAL;
  190.  
  191. {****************************************************************************}
  192. {*                                                                          *}
  193. {*  Procedure ComWriteCh(ComPort:Byte; Ch:Char); External                   *}
  194. {*                                                                          *}
  195. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  196. {*  Ch:Char       ->  Character to send                                     *}
  197. {*                                                                          *}
  198. {*  Places the character [Ch] in the transmit buffer of the specified port. *}
  199. {*  If the port specified is not open or nonexistent, or if the buffer is   *}
  200. {*  filled, the character is discarded.  Written in assembly language to    *}
  201. {*  maximize performance (see ASYNC.ASM)                                    *}
  202. {*                                                                          *}
  203. {****************************************************************************}
  204.  
  205. PROCEDURE ComWriteCh(ComPort : BYTE; Ch : CHAR); EXTERNAL;
  206.  
  207. {****************************************************************************}
  208. {*                                                                          *}
  209. {*  Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;                 *}
  210. {*                                                                          *}
  211. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  212. {*  Ch:Char       ->  Character to send                                     *}
  213. {*                                                                          *}
  214. {*  Works as ComWriteCh, but will wait until at least 1 free position is    *}
  215. {*  available in the output buffer before attempting to place the character *}
  216. {*  [Ch] in it.  Allows the programmer to send characters without regard to *}
  217. {*  available buffer space.  Written in assembly language to maximize       *}
  218. {*  performance (see ASYNC.ASM)                                             *}
  219. {*                                                                          *}
  220. {****************************************************************************}
  221.  
  222. PROCEDURE ComWriteChW(ComPort : BYTE; Ch : CHAR); EXTERNAL;
  223.  
  224. {****************************************************************************}
  225. {*                                                                          *}
  226. {*  Procedure SetDTR(ComPort:Byte; Assert:Boolean);                         *}
  227. {*                                                                          *}
  228. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  229. {*                      Call ignored if out-of-range                        *}
  230. {*  Assert:Boolean  ->  DTR assertion flag (TRUE to assert DTR)             *}
  231. {*                                                                          *}
  232. {*  Provides a means to control the port's DTR (Data Terminal Ready) signal *}
  233. {*  line.  When [Assert] is TRUE, the DTR line is placed in the "active"    *}
  234. {*  state, signalling to a remote system that the host is "on-line"         *}
  235. {*  (although not nessesarily ready to receive data - see SetRTS).          *}
  236. {*                                                                          *}
  237. {****************************************************************************}
  238.  
  239. PROCEDURE SetDTR(ComPort : BYTE; Assert : BOOLEAN);
  240. VAR
  241.   P,X : INTEGER;
  242. BEGIN
  243.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN EXIT;
  244.   P := C_PortAddr[ComPort];
  245.   X := Port[P + C_MCR];
  246.   IF Assert THEN
  247.     X := X OR $01
  248.   ELSE
  249.     X := X AND $FE;
  250.   Port[P + C_MCR] := X;
  251. END;
  252.  
  253. {****************************************************************************}
  254. {*                                                                          *}
  255. {*  Procedure SetRTS(ComPort:Byte; Assert:Boolean)                          *}
  256. {*                                                                          *}
  257. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  258. {*                      Call ignored if out-of-range                        *}
  259. {*  Assert:Boolean  ->  RTS assertion flag (Set TRUE to assert RTS)         *}
  260. {*                                                                          *}
  261. {*  SetRTS allows a program to manually control the Request-To-Send (RTS)   *}
  262. {*  signal line.  If RTS handshaking is disabled (see C_Ctrl definition     *}
  263. {*  and the the SetRTSMode procedure), this procedure may be used.  SetRTS  *}
  264. {*  should NOT be used if RTS handshaking is enabled.                       *}
  265. {*                                                                          *}
  266. {****************************************************************************}
  267.  
  268. PROCEDURE SetRTS(ComPort : BYTE; Assert : BOOLEAN);
  269. VAR
  270.   P,X : INTEGER;
  271. BEGIN
  272.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN EXIT;
  273.   P := C_PortAddr[ComPort];
  274.   X := Port[P + C_MCR];
  275.   IF Assert THEN
  276.     X := X OR $02
  277.   ELSE
  278.     X := X AND $FD;
  279.   Port[P + C_MCR] := X;
  280. END;
  281.  
  282. {****************************************************************************}
  283. {*                                                                          *}
  284. {*  Procedure SetOUT1(ComPort:Byte; Assert:Boolean)                         *}
  285. {*                                                                          *}
  286. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  287. {*                      Call ignored if out-of-range                        *}
  288. {*  Assert:Boolean  ->  OUT1 assertion flag (set TRUE to assert OUT1 line)  *}
  289. {*                                                                          *}
  290. {*  SetOUT1 is provided for reasons of completeness only, since the         *}
  291. {*  standard PC/XT/AT configurations do not utilize this control signal.    *}
  292. {*  If [Assert] is TRUE, the OUT1 signal line on the 8250 will be set to a  *}
  293. {*  LOW logic level (inverted logic).  The OUT1 signal is present on pin 34 *}
  294. {*  of the 8250 (but not on the port itself).                               *}
  295. {*                                                                          *}
  296. {****************************************************************************}
  297. {
  298. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  299. Var
  300.   P,X : Integer;
  301. Begin
  302.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  303.   P := C_PortAddr[ComPort];
  304.   X := Port[P+C_MCR];
  305.   If Assert Then
  306.     X := X Or $04
  307.   Else
  308.     X := X And $FB;
  309.   Port[P+C_MCR] := X;
  310. End;
  311.  }
  312. {****************************************************************************}
  313. {*                                                                          *}
  314. {*  Procedure SetOUT2(ComPort:Byte; Assert:Boolean)                         *}
  315. {*                                                                          *}
  316. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  317. {*                      Call ignored if out-of-range                        *}
  318. {*  Assert:Boolean  ->  OUT2 assertion flag (set TRUE to assert OUT2 line)  *}
  319. {*                                                                          *}
  320. {*  The OUT2 signal line, although not available on the port itself, is     *}
  321. {*  used to gate the 8250 <INTRPT> (interrupt) line and thus acts as a      *}
  322. {*  redundant means of controlling 8250 interrupts.  When [Assert] is TRUE, *}
  323. {*  the /OUT2 line on the 8250 is lowered, which allows the passage of the  *}
  324. {*  <INTRPT> signal through a gating arrangement, allowing the 8250 to      *}
  325. {*  generate interrupts.  Int's can be disabled bu unASSERTing this line.   *}
  326. {*                                                                          *}
  327. {****************************************************************************}
  328. {
  329. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  330. Var
  331.   P,X : Integer;
  332. Begin
  333.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  334.   P := C_PortAddr[ComPort];
  335.   X := Port[P+C_MCR];
  336.   If Assert Then
  337.     X := X Or $08
  338.   Else
  339.     X := X And $F7;
  340.   Port[P+C_MCR] := X;
  341. End;
  342.  }
  343. {****************************************************************************}
  344. {*                                                                          *}
  345. {*  Function CTSStat(ComPort:Byte) : Boolean                                *}
  346. {*                                                                          *}
  347. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  348. {*                    Call ignored if out-of-range                          *}
  349. {*  Returns status of Clear-To-Send line (TRUE if CTS asserted)             *}
  350. {*                                                                          *}
  351. {*  CTSStat provides a means to interrogate the Clear-To-Send hardware      *}
  352. {*  handshaking line.  In a typical arrangement, when CTS is asserted, this *}
  353. {*  signals the host (this computer) that the receiver is ready to accept   *}
  354. {*  data (in contrast to the DSR line, which signals the receiver as        *}
  355. {*  on-line but not nessesarily ready to accept data).  An automated mech-  *}
  356. {*  ansim (see CTSMode) is provided to do this, but in cases where this is  *}
  357. {*  undesirable or inappropriate, the CTSStat function can be used to int-  *}
  358. {*  terrogate this line manually.                                           *}
  359. {*                                                                          *}
  360. {****************************************************************************}
  361.  
  362. FUNCTION CTSStat(ComPort : BYTE) : BOOLEAN;
  363. BEGIN
  364.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  365.     CTSStat := FALSE
  366.   ELSE
  367.     CTSStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $10 <> $10);
  368. END;
  369.  
  370. {****************************************************************************}
  371. {*                                                                          *}
  372. {*  Function RTSStat(ComPort:Byte) : Boolean                                *}
  373. {*                                                                          *}
  374. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  375. {*                    Call ignored if out-of-range                          *}
  376. {*  Returns status of Ready-To-Send line (TRUE if RTS asserted)             *}
  377. {*                                                                          *}
  378. {****************************************************************************}
  379.  
  380.  
  381. FUNCTION RTSStat(ComPort : BYTE) : BOOLEAN;
  382. BEGIN
  383.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  384.     RTSStat := FALSE
  385.   ELSE
  386.     RTSStat := (Port[C_PortAddr[ComPort] + C_LSR] AND $20 <> $20);
  387. END;
  388.  
  389. {****************************************************************************}
  390. {*                                                                          *}
  391. {*  Function DSRStat(ComPort:Byte) : Boolean                                *}
  392. {*                                                                          *}
  393. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  394. {*                    Call ignored if out-of-range                          *}
  395. {*  Returns status of Data Set Ready (DSR) signal line.                     *}
  396. {*                                                                          *}
  397. {*  The Data Set Ready (DSR) line is typically used by a remote station     *}
  398. {*  to signal the host system that it is on-line (although not nessesarily  *}
  399. {*  ready to receive data yet - see CTSStat).  A remote station has the DSR *}
  400. {*  line asserted if DSRStat returns TRUE.                                  *}
  401. {*                                                                          *}
  402. {****************************************************************************}
  403.  
  404. FUNCTION DSRStat(ComPort : BYTE) : BOOLEAN;
  405. BEGIN
  406.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  407.     DSRStat := FALSE
  408.   ELSE
  409.     DSRStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $20) > 0;
  410. END;
  411.  
  412. {****************************************************************************}
  413. {*                                                                          *}
  414. {*  Function RIStat(ComPort:Byte) : Boolean                                 *}
  415. {*                                                                          *}
  416. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  417. {*                    Call ignored if out-of-range                          *}
  418. {*                                                                          *}
  419. {*  Returns the status of the Ring Indicator (RI) line.  This line is       *}
  420. {*  typically used only by modems, and indicates that the modem has detect- *}
  421. {*  ed an incoming call if RIStat returns TRUE.                             *}
  422. {*                                                                          *}
  423. {****************************************************************************}
  424.  
  425. FUNCTION RIStat(ComPort : BYTE) : BOOLEAN;
  426. BEGIN
  427.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  428.     RIStat := FALSE
  429.   ELSE
  430.     RIStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $40) > 0;
  431. END;
  432.  
  433. {****************************************************************************}
  434. {*                                                                          *}
  435. {*  Function DCDStat(ComPort:Byte) : Boolean                                *}
  436. {*                                                                          *}
  437. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  438. {*                    Call ignored if out-of-range                          *}
  439. {*                                                                          *}
  440. {*  Returns the status of the Data Carrier Detect (DCD) line from the rem-  *}
  441. {*  ote device, typically a modem.  When asserted (DCDStat returns TRUE),   *}
  442. {*  the modem indicates that it has successfuly linked with another modem   *}
  443. {*  device at another site.                                                 *}
  444. {*                                                                          *}
  445. {****************************************************************************}
  446.  
  447. FUNCTION DCDStat(ComPort : BYTE) : BOOLEAN;
  448. BEGIN
  449.   IF (ComPort < 1) OR (ComPort > C_MaxCom) THEN
  450.     DCDStat := FALSE
  451.   ELSE
  452.     DCDStat := (Port[C_PortAddr[ComPort] + C_MSR] AND $80) > 0;
  453. END;
  454.  
  455. {****************************************************************************}
  456. {*                                                                          *}
  457. {*  Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word)     *}
  458. {*                                                                          *}
  459. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  460. {*                    Request ignored if out of range or unopened.          *}
  461. {*  Mode:Boolean  ->  TRUE to enable automatic RTS handshake                *}
  462. {*  RTSOn:Word    ->  Buffer-usage point at which the RTS line is asserted  *}
  463. {*  RTSOff:Word   ->  Buffer-usage point at which the RTS line is dropped   *}
  464. {*                                                                          *}
  465. {*  SetRTSMode enables or disables automated RTS handshaking.  If [MODE] is *}
  466. {*  TRUE, automated RTS handshaking is enabled.  If enabled, the RTS line   *}
  467. {*  will be DROPPED when the # of buffer bytes used reaches or exceeds that *}
  468. {*  of [RTSOff].  The RTS line will then be re-asserted when the buffer is  *}
  469. {*  emptied down to the [RTSOn] usage point.  If either [RTSOn] or [RTSOff] *}
  470. {*  exceeds the input buffer size, they will be forced to (buffersize-1).   *}
  471. {*  If [RTSOn] > [RTSOff] then [RTSOn] will be the same as [RTSOff].        *}
  472. {*  The actual handshaking control is located in the interrupt driver for   *}
  473. {*  the port (see ASYNC.ASM).                                               *}
  474. {*                                                                          *}
  475. {****************************************************************************}
  476.  
  477. PROCEDURE SetRTSMode(ComPort : BYTE; Mode : BOOLEAN; RTSOn,RTSOff : WORD);
  478. VAR
  479.   X : BYTE;
  480. BEGIN
  481.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  482.  
  483.   X := C_Ctrl[ComPort];
  484.   IF Mode THEN X := X OR $01 ELSE X := X AND $FE;
  485.   C_Ctrl[ComPort] := X;
  486.   IF Mode THEN
  487.     BEGIN
  488.       IF (RTSOff >= C_InSize[ComPort]) THEN RTSOff := C_InSize[ComPort] - 1;
  489.       IF (RTSOn > RTSOff) THEN RTSOff := RTSOn;
  490.       C_RTSOn[ComPort] := RTSOn;
  491.       C_RTSOff[ComPort] := RTSOff;
  492.     END;
  493. END;
  494.  
  495. {****************************************************************************}
  496. {*                                                                          *}
  497. {*  Procedure SetCTSMode(ComPort:Byte; Mode:Boolean)                        *}
  498. {*                                                                          *}
  499. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  500. {*                    Request ignored if out of range or unopened.          *}
  501. {*  Mode:Boolean  ->  Set to TRUE to enable automatic CTS handshake.        *}
  502. {*                                                                          *}
  503. {*  SetCTSMode allows the enabling or disabling of automated CTS handshak-  *}
  504. {*  ing.  If [Mode] is TRUE, CTS handshaking is enabled, which means that   *}
  505. {*  if the remote drops the CTS line, the transmitter will be disabled      *}
  506. {*  until the CTS line is asserted again.  Automatic handshake is disabled  *}
  507. {*  if [Mode] is FALSE.  CTS handshaking and "software" handshaking (pro-   *}
  508. {*  vided by the SoftHandshake procedure) ARE compatable and may be used    *}
  509. {*  in any combination.  The actual logic for CTS handshaking is located    *}
  510. {*  in the communications interrupt driver (see ASYNC.ASM).                 *}
  511. {*                                                                          *}
  512. {****************************************************************************}
  513.  
  514. PROCEDURE SetCTSMode(ComPort : BYTE; Mode : BOOLEAN);
  515. VAR
  516.   X : BYTE;
  517. BEGIN
  518.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  519.   X := C_Ctrl[ComPort];
  520.   IF Mode THEN X := X OR $02 ELSE X := X AND $FD;
  521.   C_Ctrl[ComPort] := X;
  522. END;
  523.  
  524. {****************************************************************************}
  525. {*                                                                          *}
  526. {*  Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char)    *}
  527. {*                                                                          *}
  528. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  529. {*                    Request ignored if out of range or unopened.          *}
  530. {*  Mode:Boolean  ->  Set to TRUE to enable transmit software handshake     *}
  531. {*  Start:Char    ->  START control character (usually ^Q)                  *}
  532. {*                    Defaults to ^Q if character passed is >= <Space>      *}
  533. {*  Stop:Char     ->  STOP control character (usually ^S)                   *}
  534. {*                    Defaults to ^S if character passed is >= <Space>      *}
  535. {*                                                                          *}
  536. {*  SoftHandshake controls the usage of "Software" (control-character)      *}
  537. {*  handshaking on transmission.  If "software handshake" is enabled        *}
  538. {*  ([Mode] is TRUE), transmission will be halted if the character in       *}
  539. {*  [Stop] is received.  Transmission is re-enabled if the [Start] char-    *}
  540. {*  acter is received.  Both the [Start] and [Stop] characters MUST be      *}
  541. {*  CONTROL characters (i.e. Ord(Start) and Ord(Stop) must both be < 32).   *}
  542. {*  Also, <Start> and <Stop> CANNOT be the same character.  If either one   *}
  543. {*  of these restrictions are violated, the defaults (^Q for <Start> and ^S *}
  544. {*  for <Stop>) will be used.  Software handshaking control is implimented  *}
  545. {*  within the communications interrupt driver (see ASYNC.ASM).             *}
  546. {*                                                                          *}
  547. {****************************************************************************}
  548.  
  549. PROCEDURE SoftHandshake(ComPort : BYTE; Mode : BOOLEAN; Start,Stop : CHAR);
  550. VAR
  551.   X : BYTE;
  552. BEGIN
  553.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  554.   X := C_Ctrl[ComPort];
  555.   IF Mode THEN
  556.     BEGIN
  557.       X := X OR $04;
  558.       IF Start = Stop THEN BEGIN Start := ^Q; Stop := ^S; END;
  559.       IF Start > #32 THEN Start := ^Q;
  560.       IF Stop > #32 THEN Stop := ^S;
  561.       C_StartChar[ComPort] := Start;
  562.       C_StopChar[ComPort] := Stop;
  563.     END
  564.   ELSE
  565.     X := X AND $FB;
  566.   C_Ctrl[ComPort] := X;
  567. END;
  568.  
  569. {****************************************************************************}
  570. {*                                                                          *}
  571. {*  Procedure ClearCom(ComPort:Byte); IO:Char)                              *}
  572. {*                                                                          *}
  573. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  574. {*                    Request ignored if out of range or unopened.          *}
  575. {*  IO:Char       ->  Action code; I=Input, O=Output, B=Both                *}
  576. {*                    No action taken if action code unrecognized.          *}
  577. {*                                                                          *}
  578. {*  ClearCom allows the user to completely clear the contents of either     *}
  579. {*  the input (receive) and/or output (transmit) buffers.  The "action      *}
  580. {*  code" passed in <IO> determines if the input (I) or output (O) buffer   *}
  581. {*  is cleared.  Action code (B) will clear both buffers.  This is useful   *}
  582. {*  if you wish to cancel a transmitted message or ignore part of a         *}
  583. {*  received message.                                                       *}
  584. {*                                                                          *}
  585. {****************************************************************************}
  586.  
  587. PROCEDURE ClearCom(ComPort : BYTE; IO : CHAR);
  588. VAR
  589.   P,X : WORD;
  590. BEGIN
  591.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  592.   IO := UPCASE(IO);
  593.   P := C_PortAddr[ComPort];
  594.   INLINE($FA);
  595.   IF (IO = 'I') OR (IO = 'B') THEN
  596.     BEGIN
  597.       C_InHead[ComPort] := 0;
  598.       C_InTail[ComPort] := 0;
  599.       C_Status[ComPort] := (C_Status[ComPort] AND $EC) OR $01;
  600.       X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  601.     END;
  602.   IF (IO = 'O') OR (IO = 'B') THEN
  603.     BEGIN
  604.       C_OutHead[ComPort] := 0;
  605.       C_OutTail[ComPort] := 0;
  606.       C_Status[ComPort] := (C_Status[ComPort] AND $D3) OR $04;
  607.       X := Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  608.     END;
  609.   INLINE($FB);
  610. END;
  611.  
  612. {****************************************************************************}
  613. {*                                                                          *}
  614. {*  Procedure ComBufferLeft(ComPort:Byte; IO:Char) : Word                   *}
  615. {*                                                                          *}
  616. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  617. {*                    Returns 0 if Port # invalid or unopened.              *}
  618. {*  IO:Char       ->  Action code; I=Input, O=Output                        *}
  619. {*                    Returns 0 if action code unrecognized.                *}
  620. {*                                                                          *}
  621. {*  ComBufferLeft will return a number (bytes) indicating how much space    *}
  622. {*  remains in the selected buffer.  The INPUT buffer is checked if <IO> is *}
  623. {*  (I), and the output buffer is interrogated when <IO> is (O).  Any other *}
  624. {*  "action code" will return a result of 0.  Use this function when it is  *}
  625. {*  important to avoid program delays due to calls to output procedures or  *}
  626. {*  to prioritize the reception of data (to prevent overflows).             *}
  627. {*                                                                          *}
  628. {****************************************************************************}
  629.  
  630. FUNCTION ComBufferLeft(ComPort : BYTE; IO : CHAR) : WORD;
  631. BEGIN
  632.   ComBufferLeft := 0;
  633.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  634.   IO := UPCASE(IO);
  635.   IF IO = 'I' THEN
  636.     IF C_InHead[ComPort] >= C_InTail[ComPort] THEN
  637.       ComBufferLeft := C_InSize[ComPort] - (C_InHead[ComPort] - C_InTail[ComPort])
  638.     ELSE
  639.       ComBufferLeft := C_InTail[ComPort] - C_InHead[ComPort];
  640.   IF IO = 'O' THEN
  641.     IF C_OutHead[ComPort] >= C_OutTail[ComPort] THEN
  642.       ComBufferLeft := C_OutHead[ComPort] - C_OutTail[ComPort]
  643.     ELSE
  644.       ComBufferLeft := C_OutSize[ComPort] - (C_OutTail[ComPort] - C_OutHead[ComPort]);
  645. END;
  646.  
  647. {****************************************************************************}
  648. {*                                                                          *}
  649. {*  Procedure ComWaitForClear(ComPort:Byte)                                 *}
  650. {*                                                                          *}
  651. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  652. {*                    Exits immediately if out of range or port unopened.   *}
  653. {*                                                                          *}
  654. {*  A call to ComWaitForClear will stop processing until the selected out-  *}
  655. {*  put buffer is completely emptied.  Typically used just before a call    *}
  656. {*  to the CloseCom procedure to prevent premature cut-off of messages in   *}
  657. {*  transit.                                                                *}
  658. {*                                                                          *}
  659. {****************************************************************************}
  660.  
  661. PROCEDURE ComWaitForClear(ComPort : BYTE);
  662. VAR
  663.   Empty : BOOLEAN;
  664. BEGIN
  665.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  666.   REPEAT
  667.     Empty := (C_Status[ComPort] AND $04) = $04;
  668.     Empty := Empty AND ((Port[C_PortAddr[ComPort] + C_IER] AND $02) = $00);
  669.   UNTIL Empty;
  670. END;
  671.  
  672. {****************************************************************************}
  673. {*                                                                          *}
  674. {*  Procedure ComWrite(ComPort:Byte; St:String)                             *}
  675. {*                                                                          *}
  676. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  677. {*                    Exits immediately if out of range or port unopened.   *}
  678. {*  St:String     ->  String to send                                        *}
  679. {*                                                                          *}
  680. {*  Sends string <St> out communications port <ComPort>.                    *}
  681. {*                                                                          *}
  682. {****************************************************************************}
  683.  
  684. PROCEDURE I_ComWrite(ComPort : BYTE; St : STRING);
  685. VAR
  686.   X : BYTE;
  687. BEGIN
  688.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  689.   FOR X := 1 TO LENGTH(St) DO ComWriteChW(ComPort,St[X]);
  690. END;
  691.  
  692. {****************************************************************************}
  693. {*                                                                          *}
  694. {*  Procedure ComWriteln(ComPort:Byte; St:String);                          *}
  695. {*                                                                          *}
  696. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  697. {*                    Exits immediately if out of range or port unopened.   *}
  698. {*  St:String     ->  String to send                                        *}
  699. {*                                                                          *}
  700. {*  Sends string <St> with a CR and LF appended.                            *}
  701. {*                                                                          *}
  702. {****************************************************************************}
  703.  
  704. PROCEDURE I_ComWriteln(ComPort : BYTE; St : STRING);
  705. VAR
  706.   X : BYTE;
  707. BEGIN
  708.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  709.   FOR X := 1 TO LENGTH(St) DO ComWriteChW(ComPort,St[X]);
  710.   ComWriteChW(ComPort,#13);
  711.   ComWriteChW(ComPort,#10);
  712. END;
  713.  
  714. {****************************************************************************}
  715. {*                                                                          *}
  716. {*  Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);         *}
  717. {*                                                                          *}
  718. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  719. {*                    Exits immediately if out of range or port unopened.   *}
  720. {*  St:String     ->  String to send                                        *}
  721. {*  Dly:Word      ->  Time, in milliseconds, to delay between each char.    *}
  722. {*                                                                          *}
  723. {*  ComWriteWithDelay will send string <St> to port <ComPort>, delaying     *}
  724. {*  for <Dly> milliseconds between each character.  Useful for systems that *}
  725. {*  cannot keep up with transmissions sent at full speed.                   *}
  726. {*                                                                          *}
  727. {****************************************************************************}
  728.  
  729. PROCEDURE I_ComWriteWithDelay(ComPort : BYTE; St : STRING; Dly : WORD);
  730. VAR
  731.   X : BYTE;
  732. BEGIN
  733.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  734.   ComWaitForClear(ComPort);
  735.   FOR X := 1 TO LENGTH(St) DO BEGIN
  736.     ComWriteChW(ComPort,St[X]);
  737.     ComWaitForClear(ComPort);
  738.     DELAY(Dly);
  739.   END;
  740. END;
  741.  
  742. {****************************************************************************}
  743. {*                                                                          *}
  744. {* Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean)*}
  745. {*                                                                          *}
  746. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  747. {*                    Exits immediately if out of range or port unopened.   *}
  748. {*  St:String     <-  Edited string from remote                             *}
  749. {*  Size:Byte;    ->  Maximum allowable length of input                     *}
  750. {*  Echo:Boolean; ->  Set TRUE to echo received characters                  *}
  751. {*                                                                          *}
  752. {*  ComReadln is the remote equivalent of the standard Pascal READLN pro-   *}
  753. {*  cedure with some enhancements.  ComReadln will accept an entry of up to *}
  754. {*  40 printable ASCII characters, supporting ^H and ^X editing commands.   *}
  755. {*  Echo-back of the entry (for full-duplex operation) is optional.  All    *}
  756. {*  control characters, as well as non-ASCII (8th bit set) characters are   *}
  757. {*  stripped.  If <Echo> is enabled, ASCII BEL (^G) characters are sent     *}
  758. {*  when erroneous characters are intercepted.  Upon receipt of a ^M (CR),  *}
  759. {*  the procedure is terminated and the final string result returned.       *}
  760. {*                                                                          *}
  761. {****************************************************************************}
  762.  
  763. PROCEDURE I_ComReadln(ComPort : BYTE; VAR St : STRING; Size : BYTE; Echo : BOOLEAN);
  764. VAR
  765.   Len,X : BYTE;
  766.   Ch : CHAR;
  767.   Done : BOOLEAN;
  768. BEGIN
  769.   St := '';
  770.   IF (ComPort < 1) OR (ComPort > C_MaxCom) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  771.   Done := FALSE;
  772.   REPEAT
  773.     Len := LENGTH(St);
  774.     Ch := CHR(ORD(ComReadChW(ComPort)) AND $7F);
  775.     CASE Ch OF
  776.       ^H : IF Len > 0 THEN
  777.              BEGIN
  778.                DEC(Len);
  779.                St[0] := CHR(Len);
  780.                IF Echo THEN I_ComWrite(ComPort,#8#32#8);
  781.              END
  782.            ELSE
  783.              ComWriteChW(ComPort,^G);
  784.       ^M : BEGIN
  785.              Done := TRUE;
  786.              IF Echo THEN I_ComWrite(ComPort,#13#10);
  787.            END;
  788.       ^X : BEGIN
  789.              St := '';
  790.              IF Len = 0 THEN ComWriteCh(ComPort,^G);
  791.              IF Echo THEN
  792.                FOR X := 1 TO Len DO
  793.                  I_ComWrite(ComPort,#8#32#8);
  794.            END;
  795.       #32..#127 : IF Len < Size THEN
  796.                     BEGIN
  797.                       INC(Len);
  798.                       St[Len] := Ch;
  799.                       St[0] := CHR(Len);
  800.                       IF Echo THEN ComWriteChW(ComPort,Ch);
  801.                     END
  802.                   ELSE
  803.                     IF Echo THEN ComWriteChW(ComPort,^G);
  804.     ELSE
  805.       IF Echo THEN ComWriteChW(ComPort,^G)
  806.     END;
  807.  
  808.   UNTIL Done;
  809. END;
  810.  
  811. {****************************************************************************}
  812. {*                                                                          *}
  813. {*  Function ComExist(ComPort:Byte) : Boolean                               *}
  814. {*                                                                          *}
  815. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  816. {*                    Returns FALSE if out of range                         *}
  817. {*  Returns TRUE if hardware for selected port is detected & tests OK       *}
  818. {*                                                                          *}
  819. {*  Function ComExist performs a high-speed short loopback test on the      *}
  820. {*  selected port to determine if it indeed exists.  Use this function      *}
  821. {*  before attempts to OPEN a port for I/O (although this function is       *}
  822. {*  called by OpenCom to prevent such an occurance).                        *}
  823. {*  NOTE!  Although pains are taken to preserve the 8250 state before the   *}
  824. {*  port test takes place, it is nonetheless recommended that this function *}
  825. {*  NOT be called while a port is actually OPEN.  Doing so may cause the    *}
  826. {*  port to behave erratically.                                             *}
  827. {*                                                                          *}
  828. {****************************************************************************}
  829.  
  830. FUNCTION ComExist(ComPort : BYTE) : BOOLEAN;
  831. CONST
  832.   TestByte1 : BYTE = $0F;
  833.   TestByte2 : BYTE = $F1;
  834. VAR
  835.   P : WORD;
  836.   M,L,B1,B2 : BYTE;
  837. BEGIN
  838.   ComExist := FALSE;
  839.   IF (ComPort < 1) OR (ComPort > C_MaxPort) THEN EXIT;
  840.   P := C_PortAddr[ComPort];
  841.   M := Port[P + C_MCR];                          { Save MCR }
  842.   L := Port[P + C_LCR];                          { Save LCR }
  843.   Port[P + C_MCR] := $10;                        { Enable loopback mode }
  844.   Port[P + C_LCR] := $80;                        { Enable divisor latch mode }
  845.   B1 := Port[P];                                 { Save current baud rate }
  846.   B2 := Port[P + 1];
  847.   Port[P] := 4;                                  { Set baud rate to 28000 }
  848.   Port[P + 1] := 0;
  849.   Port[P + C_LCR] := $03;                        { Transmit mode 28000:8N1 }
  850.   Port[P] := TestByte1;                          { Test byte #1 }
  851.   DELAY(20);                                     { Wait a bit for loopback }
  852.   IF Port[P] <> TestByte1 THEN EXIT;             { Exit w/error if not echoed }
  853.   Port[P] := TestByte2;                          { Test byte #2 }
  854.   DELAY(20);                                     { Wait a bit for loopback }
  855.   IF Port[P] <> TestByte2 THEN EXIT;             { Exit w/error if not echoed }
  856.   ComExist := TRUE;                              { Test passed: Port exists }
  857.   Port[P + C_LCR] := $80;                        { Restore baud rate }
  858.   Port[P] := B1;
  859.   Port[P + 1] := B2;
  860.   Port[P + C_LCR] := L;                          { Restore parameters }
  861.   Port[P + C_MCR] := M;                          { Restore control lines }
  862. END;
  863.  
  864. {****************************************************************************}
  865. {*                                                                          *}
  866. {*  Function ComTrueBaud(Baud:Longint) : Real                               *}
  867. {*                                                                          *}
  868. {*  Baud:Longint  ->  User baud rate to test.                               *}
  869. {*                    Should be between C_MinBaud and C_MaxBaud.            *}
  870. {*  Returns the actual baud rate based on the accuracy of the 8250 divider. *}
  871. {*                                                                          *}
  872. {*  The ASYNC11 communications package allows the programmer to select ANY  *}
  873. {*  baud rate, not just those that are predefined by the BIOS or other      *}
  874. {*  agency.  Since the 8250 uses a divider/counter chain to generate it's   *}
  875. {*  baud clock, many non-standard baud rates can be generated.  However,    *}
  876. {*  the binary counter/divider is not always capable of generating the      *}
  877. {*  EXACT baud rate desired by a user.  This function, when passed a valid  *}
  878. {*  baud rate, will return the ACTUAL baud rate that will be generated.     *}
  879. {*  The baud rate is based on a 8250 input clock rate of 1.73728 MHz.       *}
  880. {*                                                                          *}
  881. {****************************************************************************}
  882.  
  883. FUNCTION ComTrueBaud(Baud : LONGINT) : REAL;
  884. VAR
  885.   X : REAL;
  886.   Y : WORD;
  887. BEGIN
  888.   X := Baud;
  889.   IF X < C_MinBaud THEN X := C_MinBaud;
  890.   IF X > C_MaxBaud THEN X := C_MaxBaud;
  891.   ComTrueBaud := 115200 / ROUND($900 / (X / 50));
  892. END;
  893.  
  894. {****************************************************************************}
  895. {*                                                                          *}
  896. {*  Procedure ComParams(ComPort:Byte; Baud:Longint;                         *}
  897. {*                      WordSize:Byte; Parity:Char; StopBits:Byte);         *}
  898. {*                                                                          *}
  899. {*  ComPort:Byte   ->  Port # to initialize.  Must be (1 - C_MaxCom)        *}
  900. {*                     Procedure aborted if port # invalid or unopened.     *}
  901. {*  Baud:Longint   ->  Desired baud rate.  Should be (C_MinBaud - C_MaxBaud)*}
  902. {*                     C_MinBaud or C_MaxBaud used if out of range.         *}
  903. {*  WordSize:Byte  ->  Word size, in bits.  Must be 5 - 8 bits.             *}
  904. {*                     8-bit word used if out of range.                     *}
  905. {*  Parity:Char    ->  Parity classification.                               *}
  906. {*                     May be N)one, E)ven, O)dd, M)ark or S)pace.          *}
  907. {*                     N)one selected if classification unknown.            *}
  908. {*  StopBits:Byte  ->  # of stop bits to pad character with.  Range (1-2)   *}
  909. {*                     1 stop bit used if out of range.                     *}
  910. {*                                                                          *}
  911. {*  ComParams is used to configure an OPEN'ed port for the desired comm-    *}
  912. {*  unications parameters, namely baud rate, word size, parity form and     *}
  913. {*  # of stop bits.  A call to this procedure will set up the port approp-  *}
  914. {*  riately, as well as assert the DTR, RTS and OUT2 control lines and      *}
  915. {*  clear all buffers.                                                      *}
  916. {*                                                                          *}
  917. {****************************************************************************}
  918.  
  919. PROCEDURE ComParams(ComPort : BYTE; Baud : LONGINT; WordSize : BYTE; Parity : CHAR; StopBits : BYTE);
  920. CONST
  921.   C_Stopbit1    = $00;                 { Bit masks for parity, stopbits }
  922.   C_Stopbit2    = $04;
  923.   C_NoParity    = $00;
  924.   C_OddParity   = $08;
  925.   C_EvenParity  = $18;
  926.   C_MarkParity  = $28;
  927.   C_SpaceParity = $38;
  928. VAR
  929.   X : REAL;
  930.   Y,P : WORD;
  931.   DivMSB,DivLSB,BaudB : BYTE;
  932.   WS,SB,PTY : BYTE;
  933. BEGIN
  934.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  935.   INLINE($FA);
  936.   P := C_PortAddr[ComPort];
  937.   { Calculate baud rate divisors }
  938.   X := Baud;
  939.   IF X < C_MinBaud THEN X := C_MinBaud;
  940.   IF X > C_MaxBaud THEN X := C_MaxBaud;
  941.   Y := ROUND($900 / (X / 50));
  942.   DivMSB := HI(Y);
  943.   DivLSB := LO(Y);
  944.   { Determine parity mask }
  945.   { Default if unknown: No parity }
  946.   CASE UPCASE(Parity) OF
  947.     'N' : PTY := C_NoParity;
  948.     'E' : PTY := C_EvenParity;
  949.     'O' : PTY := C_OddParity;
  950.     'M' : PTY := C_MarkParity;
  951.     'S' : PTY := C_SpaceParity;
  952.   ELSE
  953.     PTY := C_NoParity;
  954.   END;
  955.   { Determine stop-bit mask }
  956.   { Default if out of range: 1 Stop bit }
  957.   CASE StopBits OF
  958.     1 : SB := C_StopBit1;
  959.     2 : SB := C_StopBit2;
  960.   ELSE
  961.     SB := C_StopBit1;
  962.   END;
  963.   { Determine word-size mask }
  964.   { Default if out of range: 8 bit word size }
  965.   IF (WordSize >= 5) AND (WordSize <= 8) THEN
  966.     WS := WordSize - 5
  967.   ELSE
  968.     WS := 3;
  969.   { Initialize line-control register }
  970.   Y := Port[P] + Port[P + C_LSR];
  971.   Port[P + C_LCR] := WS + SB + PTY;
  972.   { Initialize baud rate divisor latches }
  973.   Port[P + C_LCR] := Port[P + C_LCR] OR $80;
  974.   Port[P] := DivLSB;
  975.   Port[P + 1] := DivMSB;
  976.   Port[P + C_LCR] := Port[P + C_LCR] AND $7F;
  977.   X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  978.   { Assert RS323 control lines (DTR,RTS,OUT2) & exit }
  979.   Port[P + C_MCR] := $0B;
  980.   ClearCom(ComPort,'B');
  981.   {begin new stuff}
  982.   Port[$20] := $20;
  983.   IF C_CascadeOK[comport] THEN
  984.     Port[$A0] := $20;
  985.   {end new stuff}
  986.   INLINE($FB);
  987. END;
  988.  
  989. {****************************************************************************}
  990. {*                                                                          *}
  991. {*  Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word):Boolean *}
  992. {*                                                                          *}
  993. {*  ComPort:Byte        ->  Port # to OPEN (1 - C_MaxCom)                   *}
  994. {*                          Request will fail if out of range or port OPEN  *}
  995. {*  InBufferSize:Word   ->  Requested size of input (receive) buffer        *}
  996. {*  OutBufferSize:Word  ->  Requested size of output (transmit) buffer      *}
  997. {*  Returns success/fail status of OPEN request (TRUE if OPEN successful)   *}
  998. {*                                                                          *}
  999. {*  OpenCom must be called before any activity (other than existence check, *}
  1000. {*  see the ComExist function) takes place.  OpenCom initializes the        *}
  1001. {*  interrupt drivers and serial communications hardware for the selected   *}
  1002. {*  port, preparing it for I/O.  Memory for buffers is allocated on the     *}
  1003. {*  Pascal "heap", thus freeing data-segment memory for larger more data-   *}
  1004. {*  intensive programs.  Once a port has been OPENed, a call to ComParams   *}
  1005. {*  should be made to set up communications parameters (baud rate, parity   *}
  1006. {*  and the like).  Once this is done, I/O can take place on the port.      *}
  1007. {*  OpenCom will return a TRUE value if the opening procedure was success-  *}
  1008. {*  ful, or FALSE if it is not.                                             *}
  1009. {*                                                                          *}
  1010. {****************************************************************************}
  1011.  
  1012. FUNCTION OpenCom(ComPort : BYTE; InBufferSize,OutBufferSize : WORD) : BOOLEAN;
  1013. VAR
  1014.   TempVec : POINTER;
  1015.   P : WORD;
  1016.   IntLn,Cas_IntLn,X : BYTE;
  1017. BEGIN
  1018.   { Ensure that port was not previously open }
  1019.   OpenCom := FALSE;
  1020.   C_CascadeOK[comport] := FALSE;
  1021.   C_cascade[comport] := 0;
  1022.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR C_PortOpen[ComPort] THEN EXIT;
  1023.   C_msrport := c_portaddr[comport] + c_msr;
  1024.   { Clear any pending activity from 8250 interrupt queue }
  1025.   INLINE($FA);
  1026.   { Set up interrupt vectors & 8259 PIC }
  1027.   P := C_PortAddr[ComPort];
  1028.   c_oldier[comport] := port[P + c_ier];
  1029.   c_oldmcr[comport] := port[P + c_mcr];
  1030.   Port[P + C_IER] := $0D;
  1031.   X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  1032.   IntLn := C_PortInt[ComPort];
  1033.   IF IntLn > 7 THEN C_CascadeOK[comport] := TRUE;
  1034.   IF C_CascadeOK[comport] THEN
  1035.     BEGIN
  1036.       Cas_IntLn := IntLn - 8;
  1037.       GETINTVEC($70 + Cas_IntLn,TempVec);
  1038.       IF C_OldINTVec[IntLn] <> TempVec THEN
  1039.         BEGIN
  1040.           C_Cascade[comport] := 1;
  1041.           C_OldINTVec[IntLn] := TempVec;
  1042.           SETINTVEC($70 + Cas_IntLn,@Int_Handler);
  1043.           Port[$21] := Port[$21] AND (($01 SHL $02) XOR $FF);
  1044.           X := Port[$21];
  1045.           Port[$A1] := Port[$A1] AND (($01 SHL Cas_IntLn) XOR $FF);
  1046.           X := Port[$A1];
  1047.         END;
  1048.     END
  1049.   ELSE
  1050.     BEGIN
  1051.       GETINTVEC(8 + IntLn,TempVec);
  1052.       IF C_OldINTVec[IntLn] <> TempVec THEN
  1053.         BEGIN
  1054.           C_OldINTVec[IntLn] := TempVec;
  1055.           SETINTVEC(8 + IntLn,@Int_Handler);
  1056.           Port[$21] := Port[$21] AND (($01 SHL IntLn) XOR $FF);
  1057.           X := Port[$21];
  1058.         END;
  1059.     END;
  1060.   Port[P + C_MCR] := $0B;
  1061.   {new stuff (enable FIFO's, if found)}
  1062.   IF C_FifoOK[comport] THEN BEGIN
  1063.     c_oldfcr[comport] := port[c_portaddr[comport] + 2];
  1064.     {v- enable FIFO's, clear both FIFO's, and set recieve trigger level to 14}
  1065.     port[c_portaddr[comport] + 2] := $C7;
  1066.     {v- check to see if FIFO's are enabled. if not, they don't exist}
  1067.     x := (port[c_portaddr[comport] + C_IIR] AND $40) SHR 6; {get bit 6}
  1068.     c_fifoOK[comport] := (x = 1);
  1069.   END;
  1070. {end new}
  1071.   { Allocate memory for I/O buffers }
  1072.   C_InSize[ComPort] := InBufferSize;
  1073.   C_OutSize[ComPort] := OutBufferSize;
  1074.   GETMEM(C_InBufPtr[ComPort],InBufferSize);
  1075.   GETMEM(C_OutBufPtr[ComPort],OutBufferSize);
  1076.   { Set up default parameters for port }
  1077.   C_RTSOn[ComPort] := InBufferSize - 2;
  1078.   C_RTSOff[ComPort] := InBufferSize - 1;
  1079.   C_StartChar[ComPort] := ^Q;
  1080.   C_StopChar[ComPort] := ^S;
  1081.   C_PortOpen[ComPort] := TRUE;
  1082.   OpenCom := TRUE;
  1083.   INLINE($FB);
  1084. END;
  1085.  
  1086. {****************************************************************************}
  1087. {*                                                                          *}
  1088. {*  Procedure CloseCom(ComPort:Byte)                                        *}
  1089. {*                                                                          *}
  1090. {*  ComPort:Byte  ->  Port # to close                                       *}
  1091. {*                    Request ignored if port closed or out of range.       *}
  1092. {*                                                                          *}
  1093. {*  CloseCom will un-link the interrupt drivers for a port, deallocate it's *}
  1094. {*  buffers and drop the DTR and RTS signal lines for a port opened with    *}
  1095. {*  the OpenCom function.  It should be called before exiting your program  *}
  1096. {*  to ensure that the port is properly shut down.                          *}
  1097. {*  NOTE:  CloseCom shuts down a communications channel IMMEDIATELY,        *}
  1098. {*         even if there is data present in the input or output buffers.    *}
  1099. {*         Therefore, you may wish to call the ComWaitForClear procedure    *}
  1100. {*         before closing the ports.                                        *}
  1101. {*                                                                          *}
  1102. {****************************************************************************}
  1103.  
  1104. PROCEDURE CloseCom(ComPort : BYTE);
  1105. VAR
  1106.   ClosePort : BOOLEAN;
  1107.   P,IntLn,Cas_IntLn,X : WORD;
  1108. BEGIN
  1109.   IF (ComPort < 1) OR (ComPort > C_MaxPort) OR (NOT C_PortOpen[ComPort]) THEN EXIT;
  1110.   { Drop RS232 control lines (DTR,RTS,OUT2) and reset 8250 interrupt mode }
  1111.   INLINE($FA);
  1112.   P := C_PortAddr[ComPort];
  1113.   Port[P + C_IER] := c_oldier[comport];
  1114.   C_PortOpen[ComPort] := FALSE;
  1115.   { Reset INT vectors & 8259 PIC if all COMs on selected INT are closed }
  1116.   IntLn := C_PortInt[ComPort];
  1117.   ClosePort := TRUE;
  1118.   FOR X := 1 TO C_MaxCom DO
  1119.     IF C_PortOpen[X] AND (C_PortInt[X] = IntLn) THEN ClosePort := FALSE;
  1120.   IF ClosePort THEN
  1121.     IF C_CascadeOk[comport] THEN
  1122.       BEGIN
  1123.         Cas_IntLn := IntLn - 8;
  1124.         Port[$21] := Port[$21] OR ($01 SHR $02);
  1125.         X := Port[$21];
  1126.         Port[$A1] := Port[$A1] OR ($01 SHR Cas_IntLn);
  1127.         X := Port[$A1];
  1128.         SETINTVEC($70 + Cas_IntLn,C_OldINTVec[IntLn]);
  1129.       END
  1130.     ELSE
  1131.       BEGIN
  1132.         Port[$21] := Port[$21] OR ($01 SHR IntLn);
  1133.         X := Port[$21];
  1134.         SETINTVEC(8 + IntLn,C_OldINTVec[IntLn]);
  1135.       END;
  1136.   X := Port[P] + Port[P + C_LSR] + Port[P + C_MSR] + Port[P + C_IIR];
  1137. {new stuff}
  1138.   IF C_FifoOK[comport] THEN port[c_portaddr[comport] + 2] := c_oldfcr[comport];
  1139. {end new}
  1140.   { Deallocate buffers }
  1141.   FREEMEM(C_InBufPtr[ComPort],C_InSize[ComPort]);
  1142.   FREEMEM(C_OutBufPtr[ComPort],C_OutSize[ComPort]);
  1143.   INLINE($FB);
  1144. END;
  1145.  
  1146. {****************************************************************************}
  1147. {*                                                                          *}
  1148. {*  Procedure CloseAllComs                                                  *}
  1149. {*                                                                          *}
  1150. {*  CloseAllComs will CLOSE all currently OPENed ports.  See the CloseCom   *}
  1151. {*  procedure description for more details.                                 *}
  1152. {*                                                                          *}
  1153. {****************************************************************************}
  1154.  
  1155. PROCEDURE CloseAllComs;
  1156. VAR
  1157.   X : BYTE;
  1158. BEGIN
  1159.   FOR X := 1 TO C_MaxCom DO IF C_PortOpen[X] THEN CloseCom(X);
  1160. END;
  1161.  
  1162. {****************************************************************************}
  1163. {*                                                                          *}
  1164. {*                        UNIT Initialization Code                          *}
  1165. {*                                                                          *}
  1166. {****************************************************************************}
  1167.  
  1168. BEGIN
  1169.   FOR x := 1 TO C_MaxPort DO
  1170.     BEGIN
  1171.       C_PortOpen[x] := FALSE;
  1172.       C_InBufPtr[x] := NIL;
  1173.       C_OutBufPtr[x] := NIL;
  1174.       C_OldIntVec[x] := NIL;
  1175.       C_InHead[x] := 0;
  1176.       C_OutHead[x] := 0;
  1177.       C_InTail[x] := 0;
  1178.       C_OutTail[x] := 0;
  1179.       C_InSize[x] := 0;
  1180.       C_OutSize[x] := 0;
  1181.       C_RTSOn[x] := $FFFF;
  1182.       C_RTSOff[x] := $FFFF;
  1183.       C_StartChar[x] := ^Q;
  1184.       C_StopChar[x] := ^S;
  1185.       C_Status[x] := $05;
  1186.       C_Ctrl[x] := 0;
  1187.       C_XL3Ptr[x] := 0;
  1188.       C_buffull[x] := 0;
  1189.       C_cascade[x] := 0;
  1190.       C_cascadeok[x] := FALSE;
  1191.       c_oldier[x] := 0;
  1192.       c_oldmcr[x] := 0;
  1193.       c_oldfcr[x] := 0;
  1194.       c_FifoOK[x] := FALSE;
  1195.     END;
  1196. END.
  1197.